﻿using ArcFaceSDK;
using ArcFaceSDK.SDKModels;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using OpenCvSharp;
using OpenCvSharp.Extensions;
using ArcSoftFace.Utils;
using System.Drawing;
using ArcFaceSDK.Entity;
using System.Windows.Media.Imaging;

namespace FaceDemo.Services
{
    public class FaceDisplayArgs : EventArgs
    {
        /// <summary>
        /// 图片信息
        /// </summary>
        public Bitmap bitmap { get; set; }
        /// <summary>
        /// 人脸信息
        /// </summary>
        public MultiFaceInfo faceInfo { get; set; }
        /// <summary>
        /// 是否是活体
        /// </summary>
        public bool Live { get; set; }
    }

    public class FaceVideoService
    {
        private static object instance = new object();

        private static FaceVideoService _faceService = null;

        public static FaceVideoService CreateFaceVideoSvrInstance(string appid, string appkey)
        {
            lock (instance)
            {
                if (_faceService == null)
                {
                    _faceService = new FaceVideoService(appid, appkey);
                }
            }
            return _faceService;
        }


        private FaceEngine _imageEngine = new FaceEngine();


        private string _appid;

        private string _appkey;

        private bool _engineInited = false;

        private VideoCapture _capture;

        private CancellationTokenSource _cts = new CancellationTokenSource();

        private object _set_box_locker = new object();

        private bool _writ_box = false;

        #region events
        /// <summary>
        /// 摄像头图片数据
        /// </summary>
        public event EventHandler<FaceDisplayArgs> VideoDisplaying;

        #endregion

        private FaceVideoService(string appid, string appkey)
        {
            _appid = appid;
            _appkey = appkey;
            _capture = new VideoCapture(0);
        }
        /// <summary>
        /// 开启人脸框
        /// </summary>
        public void OpenBox()
        {
            lock (_set_box_locker)
            {
                _writ_box = true;
            }
        }
        /// <summary>
        /// 关闭人脸框
        /// </summary>
        public void CloseBox()
        {
            lock (_set_box_locker)
            {
                _writ_box = false;
            }
        }

        public bool InitEngines()
        {
            try
            {
                //在线激活引擎    如出现错误，1.请先确认从官网下载的sdk库已放到对应的bin中，2.当前选择的CPU为x86或者x64
                int retCode = 0;

                retCode = _imageEngine.ASFOnlineActivation(_appid, _appkey);
                if (retCode != 0 && retCode != 90114)
                {
                    MessageBox.Show("激活SDK失败,错误码:" + retCode);
                    System.Environment.Exit(0);
                }

                //初始化引擎
                DetectionMode detectMode = DetectionMode.ASF_DETECT_MODE_IMAGE;
                //Video模式下检测脸部的角度优先值
                ASF_OrientPriority videoDetectFaceOrientPriority = ASF_OrientPriority.ASF_OP_ALL_OUT;
                //Image模式下检测脸部的角度优先值
                ASF_OrientPriority imageDetectFaceOrientPriority = ASF_OrientPriority.ASF_OP_ALL_OUT;
                //人脸在图片中所占比例，如果需要调整检测人脸尺寸请修改此值，有效数值为2-32
                int detectFaceScaleVal = 16;
                //最大需要检测的人脸个数
                int detectFaceMaxNum = 15;
                //引擎初始化时需要初始化的检测功能组合
                int combinedMask = FaceEngineMask.ASF_FACE_DETECT | FaceEngineMask.ASF_FACERECOGNITION | FaceEngineMask.ASF_AGE | FaceEngineMask.ASF_GENDER | FaceEngineMask.ASF_FACE3DANGLE| FaceEngineMask.ASF_LIVENESS;
                //初始化引擎，正常值为0，其他返回值请参考http://ai.arcsoft.com.cn/bbs/forum.php?mod=viewthread&tid=19&_dsign=dbad527e
                retCode = _imageEngine.ASFInitEngine(detectMode, imageDetectFaceOrientPriority, detectFaceScaleVal, detectFaceMaxNum, combinedMask);

                //combinedMask = FaceEngineMask.ASF_FACE_DETECT | FaceEngineMask.ASF_FACERECOGNITION | FaceEngineMask.ASF_LIVENESS;
                //retCode = _videoRGBImageEngine.ASFInitEngine(detectMode, videoDetectFaceOrientPriority, detectFaceScaleVal, detectFaceMaxNum, combinedMask);

                //设置活体阈值
                _imageEngine.ASFSetLivenessParam(0.8f);


                _engineInited = retCode == 0;

                return _engineInited;
                //初始化视频模式下人脸检测引擎

            }
            catch (Exception ex)
            {
                return false;
            }
        }


        public bool StartVideoDisplay(out string msg)
        {
            if (!_engineInited)
            {
                msg = "未初始化引擎";
                return false;
            }

            _cts = new CancellationTokenSource();
            Pen p = new Pen(Color.Red, 2f);
            Pen p2 = new Pen(Color.Green, 2f);
            if (_capture.IsOpened())
            {
                Task.Run(() =>
                {
                    Mat mat = new Mat();
                    while (!_cts.IsCancellationRequested)
                    {
                        bool r = _capture.Read(mat);
                        if (r)
                        {
                            DoWork(mat, p,p2);
                        }
                        else
                        {
                            Thread.Sleep(100);
                        }
                    }
                }, _cts.Token);

                msg = "";
                return true;
            }
            else
            {
                msg = "打开摄像头失败";
                return false;
            }
        }




        public void StopVideoDisplay()
        {
            _cts.Cancel();
        }

        public float CompareFace(MultiFaceInfo mf, Bitmap face1, string filepath)
        {
            float sim = 0f;
            SingleFaceInfo sf1 = FaceUtil.GetMaxFace(mf);

            FaceFeature ff1 = FaceUtil.ExtractFeature(_imageEngine, face1, sf1);

            //读取照片信息
            using (Image image = Image.FromFile(filepath))
            {
                MultiFaceInfo mf2 = FaceUtil.DetectFace(_imageEngine, image);

                SingleFaceInfo sf2 = FaceUtil.GetMaxFace(mf2);

                FaceFeature ff2 = FaceUtil.ExtractFeature(_imageEngine, image, sf2);

                _imageEngine.ASFFaceFeatureCompare(ff1, ff2, out sim);
            }

            return sim;
        }

        private void DoWork(Mat mat, Pen diepen,Pen livePen)
        {
            using (Bitmap bitmap = BitmapConverter.ToBitmap(mat))
            {
                //从摄像头中识别人脸信息
                MultiFaceInfo mf = FaceUtil.DetectFace(_imageEngine, bitmap);

                bool live = false;

                if (mf != null && mf.faceNum > 0)
                {
                    //如果有人脸信息
                    //得到最大人脸
                    SingleFaceInfo sf = FaceUtil.GetMaxFace(mf);
                    int retCodeLiveness = -1;
                    LivenessInfo liveInfo = FaceUtil.LivenessInfo_RGB(_imageEngine, bitmap, sf, out retCodeLiveness);
                    //检测活体
                    if (retCodeLiveness.Equals(0) && liveInfo.num > 0)
                    {
                        live = true;

                    }
                    lock (_set_box_locker)
                    {
                        if (_writ_box)
                        {
                            MRECT rect = sf.faceRect;
                            //float offsetX = irVideoSource.Width * 1f / irBmpClone.Width;
                            //float offsetY = irVideoSource.Height * 1f / irBmpClone.Height;
                            float offsetX = 1f;
                            float offsetY = 1f;
                            float x = rect.left * offsetX;
                            float width = rect.right * offsetX - x;
                            float y = rect.top * offsetY;
                            float height = rect.bottom * offsetY - y;

                            using (Graphics g = Graphics.FromImage(bitmap))
                            {
                                g.DrawRectangle(live?livePen:diepen, x, y, width, height);
                            }
                        }
                    }
                }


                VideoDisplaying?.Invoke(this, new FaceDisplayArgs()
                {
                    bitmap = bitmap, 
                    faceInfo = mf, 
                    Live = live
                });
            }
        }

    }
}
